#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#include <string.h>

#define STRSIZE 100
#define NTHREAD_PALIND 4
#define NTHREAD_CRIVO 1
#define BLOCK_LOW(id,p,n) (((id)*(n))/(p))
#define BLOCK_HIGH(id,p,n) (BLOCK_LOW((id)+1,(p),(n)) - 1)

void clear_str(char *,int);
int palindrome(char *);
int get_border(FILE *, int);

int main(int argc, char *argv[]) {

    int nprocess, rank;
    char aux[STRSIZE];
    char **text = (char**)malloc(sizeof(char*));
    int asc_palindrome = 0;
    int prime;
    int s_text = 0;
    int i = 0, j = 0;
    int pa;
    int global_pa = 0;
    int boole = 0;
    int global_prime = 0;
    int pasum = 0;
    int primesum = 0;
    int pos_f;
    int pt_f = 0;
    int pt_i = 0;

    FILE *fp;
    int begin, end, size_f;

    if ((fp = fopen("wikipedia.txt","r")) == NULL) {
        printf("ERRO AO ABRIR O ARQUIVO\n");
        exit(1);
    }

    fseek(fp,0,SEEK_END);
    size_f = ftell(fp);

    //encontra o início do bloco.
    omp_set_num_threads(NTHREAD_PALIND);

    pt_i = BLOCK_LOW(j,10,size_f);
    pt_f = BLOCK_HIGH(j,10,size_f);
    fseek(fp,0,SEEK_SET);

    while ( pt_f <= size_f ) {

	    pa = 0; prime = 0; 
	    pos_f = ftell(fp);
	    s_text = 0;
	    i = 0;

	    while(pos_f < pt_f) {

			fscanf(fp,"%s",aux);
			pos_f = ftell(fp);
			text = (char**)realloc(text,sizeof(char*)*(s_text+1));
			text[i] = (char*)malloc(sizeof(char)*(strlen(aux)+1));
			strcpy(text[i],aux);
			clear_str(aux,STRSIZE);
			s_text++;
			i++;

	    }
	    #pragma omp parallel firstprivate(asc_palindrome, i, s_text, boole, aux), shared(fp,pt_f,pt_i,size_f,text), private(begin, pos_f, end) reduction(+:global_prime,global_pa)
	    {
		    global_prime = 0; global_pa = 0;
		    int rank = omp_get_thread_num();

		    begin = BLOCK_LOW(rank,NTHREAD_PALIND,s_text);
		    end = BLOCK_HIGH(rank,NTHREAD_PALIND,s_text);

		    clear_str(aux,STRSIZE);

		    for ( i = begin; i <= end; i++ ) {
			asc_palindrome = palindrome(text[i]);
			if (asc_palindrome > 0) {
			    global_pa += 1;
			    boole = crivo(NTHREAD_CRIVO,asc_palindrome);
			    global_prime += boole;
			}
		    }
	    
	    }
	    #pragma omp barrier
	    j++;
	    pt_f = BLOCK_HIGH(j,10,size_f);
	    pt_i = BLOCK_LOW(j,10,size_f);
	    pt_i = get_border(fp,pt_i);

	   for ( i = 0; i < s_text; i++ )
		free(text[i]);

    }

	free(text);

    printf("GLOBPRIME: %d\n",global_prime);

    printf("GLOBPAL: %d\n",global_pa);

    fclose(fp);

    return 0;
 }

int get_border(FILE *fp, int pos) {

    fseek(fp,pos,SEEK_SET);
    char c = fgetc(fp);
    int i = 0;

    while( c != ' ' && c != '\t' && !feof(fp)) {
        c = fgetc(fp);
        i++;
    }

    return i+pos;

}

int palindrome(char *str) {

    int i,l,j;
    int ssize = strlen(str);
    int ascii_sum = 0;

    i=0;
    j=ssize-1;
    //ignorando caracteres especiais no final de palavra, no final da palavra, exem.: (kfbrwiufh)
    for(l=j;l>=0;l--)
	if((int)str[l]<65 || ((int)str[l]>90 && (int)str[l]<97) || (int)str[l]>122 )
		j--;
	else
		break;

    //ignorando caracteres especiais no inicio de palavra, no final da palavra, exem.: (kfbrwiufh)
    for(l=0;l<=j;l++)
	if((int)str[l]<65 || ((int)str[l]>90 && (int)str[l]<97) || (int)str[l]>122 )
		i++;
	else
		break;

    //se passar aq é palimdrome
    if(j==-1)
	return 0;//isso significa e existe uma palavra com apenas simbolos especiais
    for (  ;i <= j;i++){
        if (   ((int)str[j] != (int)str[i])   &&         ((int)str[j]+32 != (int)str[i])   && ((int)str[j] != (int)str[i]+32)         )
            return 0;
        else
            ascii_sum += (i != j) ? (int)str[j] + (int)str[i] : (int)str[i];
        j--;
    }
    //printf("%s ",str);
    return ascii_sum;

}

void clear_str(char *c, int n) {

    int i = 0;

    for ( i = 0; i < n; i++ ) {
        c[i] = 0;
    }

}

